﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using DeSleeper.Client.Framework;
using DeSleeper.Client.Installation;
using DeSleeper.Library;
using DeSleeper.Library.Tasks;

namespace DeSleeper.Client.Service
{
    class ConfigureTargetsCommand : ServiceCommand    
    {
        public override string Text
        {
            get { return "configuration of precache hosts"; }
        }

        protected override void OnExecute(object parameter)
        {
            var exceptions = new List<Exception>();
            var installer = new Installer();
            var configurationArgs = parameter as ConfigureTargetsParameters;

            if (configurationArgs.EnableWakeOnLan || configurationArgs.ConfigurePowerSettings)
            {
                foreach (var machineName in configurationArgs.Targets.CompatibleAndUnknownRemote)
                {
                    try
                    {
                        installer.StageServiceFiles(machineName);
                        schedulePowerConfig(machineName, configurationArgs);
                    }
                    catch (Exception e)
                    {
                        addException(exceptions, machineName, e);
                    }
                }
            }

            if (exceptions.Count == 1)
                throw new SelfFlatteningException(string.Empty, exceptions[0]);
            else if (exceptions.Count > 1)
                throw new SelfFlatteningAggregateException(exceptions);
        }

        private void schedulePowerConfig(string machineName, ConfigureTargetsParameters args)
        {
            var commandArguments = new StringBuilder();
            if (args.ConfigurePowerSettings)
            {
                appendTimeout(commandArguments, "standby", args.MaximumIdleTimeout);
                appendTimeout(commandArguments, "disk", args.MaximumHardDriveTimeout);
                appendTimeout(commandArguments, "monitor", args.MaximumVideoTimeout);
            }
            if (args.EnableWakeOnLan)
                commandArguments.Append(" -enable-wakeonlan");

            var processStartInfo = new ProcessStartInfo
                                       {
                                           FileName = "XPowerCfg.exe",
                                           WorkingDirectory = Installer.LocalServiceFileLocation,
                                           Arguments = commandArguments.ToString(),
                                           CreateNoWindow = true
                                       };

            if (string.IsNullOrEmpty(machineName) ||
                string.Equals("localhost", machineName, StringComparison.InvariantCultureIgnoreCase))
            {
                var process = Process.Start(processStartInfo);
                process.WaitForExit();
                process.ThrowOn(errorCode => errorCode != 0);
            }
            else
            {
                processStartInfo.FileName = Path.Combine(Installer.GetRemoteServiceFileLocation(machineName),
                                                         processStartInfo.FileName);
                var remoteProcess = RemoteProcess.Start(processStartInfo, machineName);
                remoteProcess.WaitForExit();
                remoteProcess.ThrowOn(errorCode => errorCode != 0);
            }
        }

        private void appendTimeout(StringBuilder commandArguments, string type, TimeSpan? value)
        {
            if (value.HasValue)
                commandArguments.AppendFormat(" -{0}-timeout {1}", type, value);
        }

        private void addException(ICollection<Exception> exceptions, string machineName, Exception exception)
        {
            exceptions.Add(new SelfFlatteningException(
                               string.Format(
                                   @"An error occurred while attempting to configure settings on {0}.",
                                   machineName)
                               , exception));
        }
    }
}
